package com.xu.cloud.common.feign;

import com.xu.cloud.common.exception.XuCloudException;
import com.xu.cloud.common.pojo.Result;
import feign.FeignException;
import feign.Response;
import feign.codec.DecodeException;
import feign.optionals.OptionalDecoder;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
import org.springframework.cloud.openfeign.support.SpringDecoder;

import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * 解析返回结果为Result的Feign解码器
 *
 * @author xuguan
 * @since 2025/3/6
 */
public class ResultTypeFeignDecoder implements feign.codec.Decoder {
    private final ObjectFactory<HttpMessageConverters> messageConverters;
    private final feign.codec.Decoder delegate;

    public ResultTypeFeignDecoder(ObjectFactory<HttpMessageConverters> messageConverters) {
        this.messageConverters = messageConverters;
        delegate = new OptionalDecoder(
                new ResponseEntityDecoder(new SpringDecoder(this.messageConverters)));
    }

    @Override
    public Object decode(Response response, Type type) throws IOException, DecodeException, FeignException {
        if (type instanceof Result) {
            return delegate.decode(response, type);
        }
        if (type instanceof ParameterizedType && ((ParameterizedType) type).getRawType() == Result.class) {
            return delegate.decode(response, type);
        }

        final Result<?> result = (Result) delegate.decode(response, new ParameterizedType() {
            @Override
            public Type[] getActualTypeArguments() {
                return new Type[]{type};
            }

            @Override
            public Type getRawType() {
                return Result.class;
            }

            @Override
            public Type getOwnerType() {
                return null;
            }
        });
        if (!result.isSuccess()) {
            throw new XuCloudException(result.getCode(), result.getMsg());
        }
        return result.getData();
    }
}
